home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 134_01 / cprofile.c < prev    next >
Text File  |  1985-08-19  |  19KB  |  765 lines

  1. /*    CPROFILE -- BDS `C' Program Profiler    */
  2.  
  3. /*    Copyright (c) 1983 by Kevin B. Kenny
  4.     Released to the BDS `C' Users' Group for non-commercial distribution.
  5.  
  6.     Kevin Kenny
  7.     729-A E. Cochise Dr.
  8.     Phoenix, Arizona   85020
  9. */
  10.  
  11. #define TITLE "CPROFILE version 83-11-14 copyright (c) 1983 by Kevin Kenny\n"
  12.  
  13. #include "bdscio.h"
  14. #include "dio.h"
  15. #include "cmdutil.h"
  16.  
  17. /*    Configuration    */
  18.  
  19. #define TOP 0x7000        /* End of usable memory.  Must be supplied
  20.                    to CLINK or L2 with the '-t' option. */
  21.  
  22. /*    Define some general-purpose pointers    */
  23.  
  24. union ptr {
  25.     unsigned i;        /* Integer representation */
  26.     unsigned * w;        /* Word pointer */
  27.     char * b;        /* Byte pointer */
  28.     };
  29.  
  30. /*    Define a long integer for the LONG.C package.     */
  31.  
  32. struct longint {
  33.     char longcont [4];
  34.     };
  35. #define LONG struct longint    /* Poor man's TYPEDEF */
  36.  
  37. /*    Define the structure of the execution profile table */
  38.  
  39. struct proftab {
  40.     unsigned pfaddr;    /* PC of the RST 6 operation */
  41.     LONG pftimes;        /* Number of times that RST was hit. */
  42.     } * ptent;
  43.  
  44. /*    Define the structure of the beginning of the run-time RST 6
  45.     interceptor/supervisor                        */
  46.  
  47. struct supvsr {
  48.     char supjmp0;        /* A JMP (0xC3) instruction */
  49.     unsigned supbdos;    /* Entry to CP/M BDOS (where the JMP goes) */
  50.     char supname [9];    /* 'cprofile' monogram to detect re-entry */
  51.     char supjmp1;        /* Another JMP (0xC3) instruction */
  52.     unsigned supinit;    /* Initialization entry into supervisor */
  53.     char supjmp2;        /* Another JMP (0xC3) instruction */
  54.     unsigned supboot;    /* Fake warmboot entry into supervisor */
  55.     unsigned suptop;    /* Upper address of the supervisor */
  56.     struct proftab * supent1;    /* Pointer to first entry in profile */
  57.     struct proftab * supnxte;    /* Pointer to next avail entry */
  58.     unsigned supbios;    /* Address to restore to BIOS transfer */
  59.     char supcmd [128];    /* CPROFILE command line saved for reload */
  60.     };
  61. union {
  62.     struct supvsr * sps;    /* Pointer to the supervisor */
  63.     void (* spf) ();
  64.     unsigned spi;        /* Integer value thereof */
  65.     } suprvp;
  66.  
  67. /*    Define the command line options    */
  68.  
  69. struct option optable [5];        /* Place to put the option table */
  70. int tabsize;                /* Size of the profile table needed */
  71. int pagelen;                /* Printer page length */
  72. int nsrcfs;                /* Number of source files supplied */
  73. char * * sfiles;            /* Names of the source files */
  74. char * srcfnptr [2];            /* Default source file pointer */
  75. char srcfnam [20];            /* Default source file */
  76.  
  77. /*    Define the I/O environment    */
  78.  
  79. char * prgnam;                /* Name of the program being analyzed*/
  80. char comfnam [20];            /* Name of the .COM file */
  81. char comfile [134];            /* I/O stream for the .COM file */
  82. char symfnam [20];            /* Name of the .SYM file */
  83. FILE symfile;                /* CHARIO stream for the .SYM file */
  84. FILE srcfile;                /* Input stream for the source file */
  85.  
  86. /*    Working storage        */
  87.  
  88. int hisargc;                /* ARGC of profiled program */
  89. char ** hisargv;            /* ARGV of profiled program */
  90. char pass2;                /* Flag = TRUE iff in analysis pass */
  91. char fnname [9];            /* Name of function being analyzed */
  92. int stmt;                /* Statement number within function */
  93. int line;                /* Line number within function */
  94. char symfnnam [9];            /* Last function read from .SYM */
  95. unsigned symtopad;            /* Upper address of last .SYM funct */
  96. char symend;                /* Flag == TRUE if at end of .SYM */
  97. char sfopen;                /* Flag == TRUE if a source file open*/
  98. char seof;                /* FLAG == TRUE at end of source file*/
  99. int slevel;                /* Depth of {} nesting in source */
  100. char sname [33];            /* Name of a symbol in source */
  101. char infunct;                /* Flag == TRUE if in funct in src */
  102. int sline;                /* Relative line # in source funct. */
  103. char slopen;                /* Flag == TRUE if in source line */
  104. int linage;                /* Number of lines on current page */
  105. int pageno;                /* Current page # */
  106.  
  107. /*    Main program    */
  108.  
  109. main (argc, argv)
  110.     int argc;
  111.     char * * argv;
  112.     {
  113.     union ptr bdosp;
  114.  
  115.     /* Test if CPROFILE is active.  If it is, this must be the second pass.
  116.        */
  117.  
  118.     pass2 = FALSE;
  119.     prgnam = argv [1];    /* Rem,ember the program name */
  120.     bdosp.i = 6;        /* Point to the BDOS entry address in lowcore*/
  121.     suprvp.spi = *bdosp.w;    /* Get the BDOS entry address (top of TPA) */
  122.     if (!strcmp (suprvp.sps -> supname, "cprofile")) pass2 = TRUE;
  123.  
  124.     /*    Scan the command line, separating CPROFILE's arguments from
  125.         the target program's.    */
  126.  
  127.     hisargv = argv = argv + 1; hisargc = 0;    /* His args start at once */
  128.     --argc;    
  129.     while (argc && strcmp (*argv, ":")) {    /* My args start with a ":" */
  130.         ++argv; --argc; ++hisargc;
  131.         }
  132.     if (pass2) dioinit (&argc, argv);
  133.  
  134.     /* Process command line options    */
  135.  
  136.     getopts (argc, argv);
  137.  
  138.     /* Call appropriate analysis routines */
  139.  
  140.     if (pass2) {
  141.         /* Second pass -- call the analyzer */
  142.  
  143.         analyze (argc, argv);
  144.         }
  145.  
  146.     else {
  147.         /* First pass -- install supervisor and call in program to
  148.             be profiled */
  149.  
  150.         if (!hisargc) {
  151.             fprintf (STD_ERR, "Command must be supplied.\n");
  152.             goto synerr;
  153.             }
  154.         fprintf (STD_ERR, TITLE);
  155.         install ();
  156.         fprintf (STD_ERR, "<<< Loading target program. >>>\n");
  157.         chain (hisargc, hisargv, &(suprvp.sps -> supjmp1));
  158.         }
  159. synerr:
  160.     dioflush ();
  161.     }
  162.  
  163. /*    Process command line options    */
  164.  
  165. getopts (argc, argv)
  166.     int argc;
  167.     char ** argv;
  168.     {
  169.     char error;            /* Flag = TRUE iff command erroneous */
  170.     union {
  171.         int ii;
  172.         char * si;
  173.         char * * msi;
  174.         } info;
  175.     
  176.     /* Define the available options */
  177.  
  178.     initv (optable, EOF,
  179. #define STRG_OPT -1
  180.         "Linecount", NVAL_KWD,
  181. #define LCNT_OPT 0
  182.         "PageLength", NVAL_KWD,
  183. #define PLEN_OPT 1
  184.         "SourceFiles", MSVL_KWD,
  185. #define SFIL_OPT 2
  186.         EOF);
  187.  
  188.     ++argv; --argc;            /* Discard colon separator */
  189.  
  190.     error = FALSE;
  191.     tabsize = 512 * sizeof ptent;
  192.     pagelen = 58;
  193.     srcfnptr [1] = & srcfnam;
  194.     strcpy (srcfnam, hisargv [0]);
  195.     makeext (srcfnam, "C");
  196.     sfiles = & srcfnptr;
  197.     nsrcfs = 1;
  198.  
  199.     while (argc > 0) {
  200.         switch (procarg (&argc, &argv, optable, &info)) {
  201.             case STRG_OPT:
  202.                 break;        /* Discard redirection */
  203.             case LCNT_OPT:
  204.                 tabsize = info.ii * sizeof (* ptent);
  205.                 break;
  206.             case PLEN_OPT:
  207.                 pagelen = info.ii;
  208.                 break;
  209.             case SFIL_OPT:
  210.                 nsrcfs = * (sfiles = info.msi);
  211.                 break;
  212.             default:
  213.                 error=TRUE;
  214.             }
  215.         }
  216.     
  217.     if (error || hisargc < 1) {
  218.         showsyntax ("cprofile <command and options> : [>filename]",
  219.                 optable);
  220.         quit ();
  221.         }
  222.     }
  223.  
  224.  
  225. /*    Install CPROFILE in the top of the TPA    */
  226.  
  227. install () {
  228.     struct ptr p, q;        /* Working pointer */    
  229.     void superv ();            /* The supervisor's code */
  230.     unsigned * supervrl ();        /* The supervisor's relocation table */
  231.     unsigned suprvs;        /* Size of the supervisor */
  232.     unsigned offset;        /* Relocation factor for supervisor */
  233.     unsigned nrelocs;        /* Number of relocated words in sup */
  234.  
  235.     /* Find the top of the TPA.  Using this, the size of the supervisor,
  236.        and the size of the profile table, find where the supervisor origin
  237.        will be.  */
  238.  
  239.     p.i = 6;            /* Get address of BDOS jump + 1 */
  240.     p.i = *p.w;            /* Get address of TPA top. */
  241.     suprvp.spf = &superv;        /* Point to current supervisor origin*/
  242.     suprvs = suprvp.sps -> suptop - suprvp.spi;    
  243.                     /* Get its length */
  244.     p.i = (p.i - suprvs - tabsize) & 0xFF00;
  245.                     /* Find new supervisor origin */
  246.     if (p.i < TOP) {
  247.         fprintf (STD_ERR, 
  248.             "Profile table overlays CPROFILE; use smaller -L\n");
  249.         quit ();
  250.         }
  251.  
  252.     /* Move the supervisor into place */
  253.  
  254.     offset = p.i - suprvp.spi;
  255.     movmem (suprvp.spi, p.i, suprvs);
  256.     suprvp.spi = p.i;
  257.     
  258.     /* Relocate the supervisor */
  259.  
  260.     p.w = supervrl ();        /* Get relocation table */
  261.  
  262.     nrelocs = *p.w++;
  263.     while (nrelocs--) {
  264.         q.i = suprvp.spi + *p.w++;    /* Get a relocation address */
  265.         *q.w += offset;            /* Relocate it */
  266.         }
  267.     
  268.     /*    Link the BDOS transfer through the supervisor */
  269.  
  270.     p.i = 6;
  271.     suprvp.sps -> supbdos = *p.w;
  272.     *p.w = suprvp.spi;
  273.  
  274.     /*    Link the BIOS warmboot transfer through the supervisor */
  275.  
  276.     p.i = 1;
  277.     p.i = *p.w + 1;
  278.     suprvp.sps -> supbios = *p.w;
  279.     *p.w = &(suprvp.sps -> supjmp2);
  280.  
  281.     /*    Record the CPROFILE command line in the supervisor for reload*/
  282.  
  283.     movmem (0x0080, &(suprvp.sps -> supcmd), 128);
  284.     }
  285.  
  286. /*    Analyze the results of a profiled run    */
  287.  
  288. an